(module set mzscheme

  (require "private/require.ss")
  (require-contracts)
  (require-etc)
  (require-class)

  (require ;;"private/contracts.ss"
           "set/set-interface.ss"
           "set/unordered-set.ss"
           "set/ordered-set.ss"
           "set/hashed-set.ss")
  
  (provide/contract
   ;; Type predicate
   [set? predicate/c]
   [set/c flat-contract?]
   [non-empty-set/c flat-contract?]
   [set-of/c (flat-contract/c . -> . flat-contract?)]
   [non-empty-set-of/c (flat-contract/c . -> . flat-contract?)]
   ;; Constructors
   [make-ordered ([comparison/c] (listof any/c) . ->* . [set/c])]
   [make-hashed ([hash-fn/c equality/c] (listof any/c) . ->* . [set/c])]
   [make-unordered ([equality/c] (listof any/c) . ->* . [set/c])]
   [make-eq ([] (listof any/c) . ->* . [set/c])]
   [make-eqv ([] (listof any/c) . ->* . [set/c])]
   [make-equal ([] (listof any/c) . ->* . [set/c])]
   [list->ordered (comparison/c (listof any/c) . -> . set/c)]
   [list->hashed (hash-fn/c equality/c (listof any/c) . -> . set/c)]
   [list->unordered (equality/c (listof any/c) . -> . set/c)]
   [list->eq ((listof any/c) . -> . set/c)]
   [list->eqv ((listof any/c) . -> . set/c)]
   [list->equal ((listof any/c) . -> . set/c)]
   ;; Operations
   [elements (set/c . -> . (listof any/c))]
   [size (set/c . -> . natural-number/c)]
   [member? (any/c set/c . -> . boolean?)]
   [lookup ([any/c set/c] [(-> any) (any/c . -> . any)] . opt-> . any)]
   [insert (any/c set/c . -> . non-empty-set/c)]
   [remove (any/c set/c . -> . set/c)]
   [select (non-empty-set/c . -> . any/c)]
   [clear (set/c . -> . set/c)]
   [rename set-empty? empty? (set/c . -> . boolean?)]
   [rename set-fold fold ((any/c any/c . -> . any/c) any/c set/c . -> . any)]
   [rename set-map map ((any/c . -> . any/c) set/c . -> . set/c)]
   [rename set-for-each for-each ((any/c . -> . any) set/c . -> . void?)]
   [rename set-filter filter ((any/c . -> . any/c) set/c . -> . set/c)]
   [any? ((any/c . -> . any/c) set/c . -> . boolean?)]
   [all? ((any/c . -> . any/c) set/c . -> . boolean?)]
   [rename set-ormap ormap ((any/c . -> . any/c) set/c . -> . boolean?)]
   [rename set-andmap andmap ((any/c . -> . any/c) set/c . -> . boolean?)]
   [union ([set/c set/c] [(any/c any/c . -> . any/c)] . opt-> . set/c)]
   [intersection
    ([set/c set/c] [(any/c any/c . -> . any/c)] . opt-> . set/c)]
   [difference (set/c set/c . -> . set/c)]
   [subset? (set/c set/c . -> . boolean?)]
   [rename set-equal? equal? (set/c set/c . -> . boolean?)]
   )

  ;; list->ordered : (Elem Elem -> (Union -1 0 1)) (Listof Elem) -> (Set Elem)
  ;; make-ordered : (Elem Elem -> (Union -1 0 1)) Elem ... -> (Set Elem)
  ;; Constructs a set with ordered elements.
  (define list->ordered make-ordered-set)
  (define (make-ordered compare . elems)
    (list->ordered compare elems))

  ;; list->hashed : (Elem -> Int) (Elem Elem -> Boolean) (Listof Elem) -> (Set Elem)
  ;; make-hashed : (Elem -> Int) (Elem Elem -> Boolean) Elem ... -> (Set Elem)
  ;; Constructs a set with hashable elements.
  (define list->hashed make-hashed-set)
  (define (make-hashed hash equ? . elems)
    (list->hashed hash equ? elems))

  ;; list->unordered : (Elem Elem -> Boolean) (Listof Elem) -> (Set Elem)
  ;; make-unordered : (Elem Elem -> Boolean) Elem ... -> (Set Elem)
  ;; Constructs a set with distinct elements.
  (define list->unordered make-unordered-set)
  (define (make-unordered equ? . elems)
    (list->unordered equ? elems))

  ;; list->eq : (Listof Elem) -> (Set Elem)
  ;; make-eq : Elem ... -> (Set Elem)
  ;; Constructs a set with elements distinguished by eq?
  (define (list->eq elements)
    (list->hashed eq-hash-code eq? elements))
  (define (make-eq . elements)
    (list->eq elements))

  ;; list->eqv : (Listof Elem) -> (Set Elem)
  ;; make-eqv : Elem ... -> (Set Elem)
  ;; Constructs a set with elements distinguished by eqv?
  (define (list->eqv elements)
    (list->unordered eqv? elements))
  (define (make-eqv . elements)
    (list->eqv elements))

  ;; list->equal : (Listof Elem) -> (Set Elem)
  ;; make-equal : Elem ... -> (Set Elem)
  ;; Constructs a set with elements distinguished by equal?
  (define (list->equal elements)
    (list->hashed equal-hash-code equal? elements))
  (define (make-equal . elements)
    (list->equal elements))

  ;; elements : (Set Elem) -> (List Elem)
  ;; Produces the elements of a set.
  (define (elements set)
    (send set elements))

  ;; insert : Elem (Set Elem) -> (Set Elem)
  ;; Produces an updated set containing the new element.
  (define (insert elem set)
    (send set insert elem))

  ;; lookup : Elem (Set Elem) [(-> A) (Elem -> B)] -> (Union A B)
  ;; Looks up an element of a set.
  ;; If found, calls the success function (default: return the element).
  ;; If not found, calls the failure function (default: return #f).
  (define (lookup elem set . rest)
    (send set lookup elem . rest))

  ;; remove : Elem (Set Elem) -> (Set Elem)
  ;; Produces an updated set without the given element.
  (define (remove elem set)
    (send set remove elem))
  
  ;; select : (Set Elem) -> Elem
  ;; Produces an element from the non-empty set.
  (define (select set)
    (send set select))

  ;; set-empty? : (Set Elem) -> Boolean
  ;; Reports whether a set is empty.
  (define (set-empty? set)
    (send set empty?))

  ;; clear : (Set Elem) -> (Set Elem)
  ;; Produces an empty set.
  (define (clear set)
    (send set clear))

  ;; size : (Set Elem) -> NaturalNumber
  ;; Produces the number of elements in the set.
  (define (size set)
    (send set size))

  ;; member? : Elem (Set Elem) -> Boolean
  ;; Reports whether an element is a member of a set.
  (define (member? elem set)
    (send set member? elem))

  ;; set-fold : (Elem T -> T) T (Set Elem) -> T
  ;; Builds up a result from each element in a set.
  (define (set-fold f init set)
    (send set fold f init))

  ;; set-map : (Elem -> Elem) (Set Elem) -> (Set Elem)
  ;; Adds the image of each set element to the result.
  (define (set-map f set)
    (send set map f))

  ;; set-for-each : (Elem -> Void) (Set Elem) -> Void
  ;; Performs an action for each element in a set.
  (define (set-for-each action set)
    (send set for-each action))

  ;; set-filter : (Elem -> Boolean) (Set Elem) -> (Set Elem)
  ;; Constructs a set containing those elements satisfying the predicate.
  (define (set-filter f set)
    (send set filter f))

  ;; any? : (Elem -> Boolean) (Set Elem) -> Boolean
  ;; Reports whether any element in the set satisfies the predicate.
  (define (any? f set)
    (send set any? f))
  (define set-ormap any?)

  ;; all? : (Elem -> Boolean) (Set Elem) -> Boolean
  ;; Reports whether all elements in the set satisfy the predicate.
  (define (all? f set)
    (send set all? f))
  (define set-andmap all?)

  ;; union : (Set Elem) (Set Elem) [(Elem Elem -> Elem)] -> (Set Elem)
  ;; Produces a set containing all elements in either set.
  ;; Combines duplicate elements using the given function,
  ;; which defaults to choosing one or the other.
  (define (union one two . rest)
    (send one union two . rest))

  ;; intersection : (Set Elem) (Set Elem) [(Elem Elem -> Elem)] -> (Set Elem)
  ;; Produces a set containing all elements present in both sets.
  ;; Combines the representatives from each set using the given function,
  ;; which defaults to choosing one or the other.
  (define (intersection one two . rest)
    (send one intersection two . rest))

  ;; difference : (Set Elem) (Set Elem) -> (Set Elem)
  ;; Produces a set containing all elements of the first argument
  ;; that are not present in the second argument.
  (define (difference one two)
    (send one difference two))

  ;; subset? : (Set Elem) (Set Elem) -> Boolean
  ;; Reports whether all elements in the first set are elements of the second.
  (define (subset? one two)
    (send one subset? two))

  ;; set-equal? : (Set Elem) (Set Elem) -> Boolean
  ;; Reports whether the sets contain the same elements.
  (define (set-equal? one two)
    (send one equal? two))
  
  )